
#include <iostream>
#include <string>
#include <cstdio>
#include <fstream>
#include <vector>

#include "datatypes.h"
#include "main.h"

#include <math.h>
#include <time.h>


using namespace std;


/* GLUT callback Handlers */

static void resize(int width, int height)  //handles resizing of the window
{
    const float ar = (float) width / (float) height;

    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity() ;
    gluPerspective(45.0, (float)width / (float)height, 1.0, 200.0);
}

static void display(void) //does our drawing for us
{
    //const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
    //const double a = t*90.0;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW); //Switch to the drawing perspective
	glLoadIdentity(); //Reset the drawing perspective
    DrawScreen();
    glutSwapBuffers();
}

void Initialize()
{
    // populates the bricklist array with all the relevent information from files.
    // need to write a loading function here but for now hard code it
    // initialize random seed
    srand (time(NULL));
    //open the file containing the position and color of all the bricks
    string line;
    int mode;
    ifstream infile;
    infile.open ("level1.txt");
    color thiscolor;
    while(getline(infile, line)) //reads in a line
    {
        if(line.compare("end") == 0)    //resetting mode to zero must happen first or else it tries to process the word "end"
        {
            //cout << "mode reset to zero" << endl;
            mode = 0;
        }
        if (mode == 1) //loading brick position and color
        {
            //cout << "start reading in data"  << endl;
            VecBrick* thisbrick = new (nothrow) VecBrick; //create local instance of a brick

            uint i = 0;     // loop counter
            uint ind = 0;   // index pointer
            string tmp[2];  // array of 2 strings (0 - 1).
            //cout << "instance created. Line length = " << line.length() << endl;

            for (i=0; i<line.length(); i++) //scans the line one character at a time
            {
                //cout << "character " << i <<  line[i] << endl;
                if (line[i] == 44) // found a comma so this string is done!!
                {
                    ind++;      // increment the index pointer to move to the next string in the array
                    i++;        // increment the character pointer so it skips the comma
                }
                //ignore spaces. Only adds the character if it's not a space
                if (line[i] != 32)
                {
                    tmp[ind].push_back(line[i]);    // append the character to the end of the string
                    //cout << "temporary value " << ind << " = " << tmp[ind] << endl;
                }
            }
            //newline->Start.A = atof(tmp[0].c_str());
            thisbrick->X = atof(tmp[0].c_str());
            thisbrick->Y = atof(tmp[1].c_str());
            thisbrick->BrickColor.R = thiscolor.R;
            thisbrick->BrickColor.G = thiscolor.G;
            thisbrick->BrickColor.B = thiscolor.B;
            thisbrick->exists = true;

            BrickList.push_back(thisbrick); //add the brick to the list
        }

        if (mode == 2) //looks for a color value and stores it in 'thiscolor' for use in the following bricks
        {
            uint i = 0;     // loop counter
            uint ind = 0;   // index pointer
            string tmp[3];  // array of 3 strings (0 - 2).
            for (i=0; i<line.length(); i++) //scans the line one character at a time
            {
                //cout << "character " << i <<  line[i] << endl;
                if (line[i] == 44) // found a comma so this string is done!!
                {
                    ind++;      // increment the index pointer to move to the next string in the array
                    i++;        // increment the character pointer so it skips the comma
                }
                //ignore spaces. Only adds the character if it's not a space
                if (line[i] != 32)
                {
                    tmp[ind].push_back(line[i]);    // append the character to the end of the string
                    //cout << "temporary value " << ind << " = " << tmp[ind] << endl;
                }
            }
            thiscolor.R = atof(tmp[0].c_str());
            thiscolor.B = atof(tmp[1].c_str());
            thiscolor.G = atof(tmp[2].c_str());

        }
        // NOTE setting the mode must be done after the switch or else it gets very very confused.
        if(line.compare("bricks") == 0)
        {
            //cout << "start reading level data" << endl;
            mode = 1;
        }
        if(line.compare("color") == 0)
        {
            mode = 2;
        }
    }
    infile.close();
    cout << "Size of brick list" << BrickList.size() << endl;

}

void DrawScreen() //draws the screen
{
    //draw the play area
    glLineWidth(5);
    glColor3f(1.0f, 1.0f, 1.0f); //set to white
    glBegin(GL_LINES);

    glVertex3f(-3.0f, -2.0f, Zoom);
    glVertex3f(3.0f, -2.0f, Zoom);
    glVertex3f(3.0f, -2.0f, Zoom);
    glVertex3f(3.0f, 2.0f, Zoom);
    glVertex3f(3.0f, 2.0f, Zoom);
    glVertex3f(-3.0f, 2.0f, Zoom);
    glVertex3f(-3.0f, 2.0f, Zoom);
    glVertex3f(-3.0f, -2.0f, Zoom);

    glEnd();

    for(UINT i=0;i<BrickList.size();i++)
    {
        // making a local instance of VecBot might not be the most efficient method here but it's the easiest
        // some bench mark tests are needed later
        VecBrick* thisbrick = BrickList.at(i); //create local instance of a brick
        //cout << "drawing brick " << i << " at position " << thisbrick->X << " , " << thisbrick->Y << endl;
          //not needed for solid shapes

        //set the color
        glColor3f(thisbrick->BrickColor.R, thisbrick->BrickColor.G, thisbrick->BrickColor.B);

        //initialize drawing
        glBegin(GL_POLYGON);

        //draw a square centered on the brick location
        glVertex3f(thisbrick->X - BrickSize/2, thisbrick->Y - BrickSize/2, Zoom);
        glVertex3f(thisbrick->X + BrickSize/2, thisbrick->Y - BrickSize/2, Zoom);
        glVertex3f(thisbrick->X + BrickSize/2, thisbrick->Y + BrickSize/2, Zoom);
        glVertex3f(thisbrick->X - BrickSize/2, thisbrick->Y + BrickSize/2, Zoom);

        glEnd(); //end drawing for bricks
    }

    //draw paddle
    glLineWidth(5);
    glColor3f(1.0f, 1.0f, 1.0f); //set to white
    glBegin(GL_POLYGON);

    glVertex3f(PaddlePos - PaddleLength/2, PaddlePosY - 0.05f, Zoom);
    glVertex3f(PaddlePos + PaddleLength/2, PaddlePosY - 0.05f, Zoom);
    glVertex3f(PaddlePos + PaddleLength/2, PaddlePosY + 0.05f, Zoom);
    glVertex3f(PaddlePos - PaddleLength/2, PaddlePosY + 0.05f, Zoom);

    glEnd();

}

//Handles all keypress events
static void key(unsigned char key, int x, int y)
{

    //cout << "The key pressed is " << key << endl;
    switch (key)
    {
        case 27 :
        case 'q':
            exit(0);
            break;

        case '+':
            Zoom += 0.1f;
            if (Zoom > -2){Zoom = -2;}
            cout << Zoom << endl;

            break;

        case '-':
            Zoom -= 0.1f;
            cout << Zoom << endl;
            break;
        case 'a':
            Angle -= 1;
            break;
        case 's':
            Angle += 1;
            break;
    }

    //glutPostRedisplay();
}

//mouse button press
void mouse(int btn, int state, int x, int y)
{
    if(btn == 0 && state == GLUT_DOWN)
    {
        cout << "button 1 clicked" << endl;
    }
    if(btn == 0 && state == GLUT_UP)
    {
        cout << "button 1 released" << endl;
    }


    if(btn == 2 && state == GLUT_DOWN) // Mouse button 2 selects vertices
    {
        cout << "button 2 clicked" << endl;
    }
    if(btn == 2 && state == GLUT_UP)
    {
        cout << "button 2 released" << endl;
    }
}

void mouseWheel(int button, int dir, int x, int y) //much better function than the mouse click wheel simulation
{
    if (dir > 0)
    {
        cout << "wheel up" << endl;
    }
    else
    {
        cout << "wheel down" << endl;
    }
}

//MOUSE MOVEMENTS!!
void mouseMove(int x, int y)
{
    //glfwGetDesktopMode( &return_struct );

    int width = glutGet(GLUT_WINDOW_WIDTH);
    float factor = (float)(width / 6.0f); //calculate the division factor to correct mouse value to oour ogl scale of -3 to +3
    PaddlePos = (float)(x / factor) - 3.0f; // find the actual position of the center of the paddle
    cout << "mouse X pos " << x << " Screen Width " << width << " Paddle Pos " << PaddlePos << endl;


}

static void idle(void)
{
    //main program loop
    // do the calculations for ball positions, collisions and stuff

    for(UINT i=0;i<BrickList.size();i++)
    {
        // check through the bricklist for collisions
        VecBrick* thisbrick = BrickList.at(i); //create local copy of a brick
        if(!thisbrick->exists) //check if the brick exists in this game right now
        {
            continue;   //skips to the next brick without checking anything
        }


        {
            //cout << thisbrick->X << " " << thisbrick->Y << endl;
        }
    }
    //now refresh the display
    glutPostRedisplay();    //yup that's all it does. Redisplays the window. Everything else works from interupts like key press or mouse click
}



/* Program entry point */

int main(int argc, char *argv[])
{
    //initialize window
    glutInit(&argc, argv);
    glutInitWindowSize(1000,600);
    glutInitWindowPosition(10,10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("Breakout 1.0");

    //set up readbacks
    glutReshapeFunc(resize);
    glutDisplayFunc(display);
    glutKeyboardFunc(key);
    glutIdleFunc(idle);
	glutMouseFunc(mouse);
	//glutMotionFunc(mouseMove);
	glutMouseWheelFunc(mouseWheel);
	glutPassiveMotionFunc(mouseMove);

    glClearColor(0,0,0,0);      //background color of window
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

    glEnable(GL_LIGHT0);
    glEnable(GL_NORMALIZE);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING);

    glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);

    glMaterialfv(GL_FRONT, GL_AMBIENT,   mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE,   mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);


    Initialize();           //initial setup

    glutMainLoop();         //start main loop

    return EXIT_SUCCESS;
}
